package com.WGrape.OJ.judge;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;

import com.WGrape.OJ.common.ErrorCode;
import com.WGrape.OJ.exception.BusinessException;
import com.WGrape.OJ.judge.codesandbox.CodeSandbox;
import com.WGrape.OJ.judge.codesandbox.CodeSandboxFactory;
import com.WGrape.OJ.judge.codesandbox.CodeSandboxProxy;
import com.WGrape.OJ.judge.codesandbox.model.ExecuteCodeRequest;
import com.WGrape.OJ.judge.codesandbox.model.ExecuteCodeResponse;
import com.WGrape.OJ.judge.strategy.JudgeContext;
import com.WGrape.OJ.model.dto.question.JudgeCase;
import com.WGrape.OJ.judge.codesandbox.model.JudgeInfo;
import com.WGrape.OJ.model.entity.Question;
import com.WGrape.OJ.model.entity.QuestionSubmit;
import com.WGrape.OJ.model.enums.QuestionSubmitJudgmentMethodEnum;
import com.WGrape.OJ.model.enums.QuestionSubmitStatusEnum;
import com.WGrape.OJ.service.ChatService;
import com.WGrape.OJ.service.QuestionService;
import com.WGrape.OJ.service.QuestionSubmitService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class JudgeServiceImpl implements JudgeService {

    @Resource
    private QuestionService questionService;
    @Resource
    private ChatService chatService;
    @Resource
    @Lazy
    private QuestionSubmitService questionSubmitService;

    @Resource
    private JudgeManager judgeManager;

    @Value("${codesandbox.type:example}")
    private String type;


    @Override
    public QuestionSubmit doJudge(long questionSubmitId,String judgmentMethod ) {
        // 1）传入题目的提交 id，获取到对应的题目、提交信息（包含代码、编程语言等）
        QuestionSubmit questionSubmit = questionSubmitService.getById(questionSubmitId);
        if (questionSubmit == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "提交信息不存在");
        }
        Long questionId = questionSubmit.getQuestionId();
        Question question = questionService.getById(questionId);
        if (question == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "题目不存在");
        }
        // 2）如果题目提交状态不为等待中，就不用重复执行了
        if (!questionSubmit.getStatus().equals(QuestionSubmitStatusEnum.WAITING.getValue())) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "题目正在判题中");
        }
        // 3）更改判题（题目提交）的状态为 “判题中”，防止重复执行
        QuestionSubmit questionSubmitUpdate = new QuestionSubmit();
        questionSubmitUpdate.setId(questionSubmitId);
        questionSubmitUpdate.setStatus(QuestionSubmitStatusEnum.RUNNING.getValue());
        boolean update = questionSubmitService.updateById(questionSubmitUpdate);
        if (!update) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "题目状态更新错误");
        }
        // 4）调用沙箱，获取到执行结果

        CodeSandbox codeSandbox = CodeSandboxFactory.newInstance(type);
        codeSandbox = new CodeSandboxProxy(codeSandbox);
        String language = questionSubmit.getLanguage();
        String code = questionSubmit.getCode();
        // 获取输入用例
        String judgeCaseStr = question.getJudgeCase();
        List<JudgeCase> judgeCaseList = JSONUtil.toList(judgeCaseStr, JudgeCase.class);
        List<String> inputList = judgeCaseList.stream().map(JudgeCase::getInput).collect(Collectors.toList());
        ExecuteCodeRequest executeCodeRequest = ExecuteCodeRequest.builder()
                .code(code)
                .language(language)
                .inputList(inputList)
                .build();

        if  (judgmentMethod.equals(QuestionSubmitJudgmentMethodEnum.DOCKER_SANDBOX.getValue())||judgmentMethod.equals(QuestionSubmitJudgmentMethodEnum.LOCAL_SANDBOX.getValue())) {
            //原生代码沙箱
        ExecuteCodeResponse executeCodeResponse = codeSandbox.executeCode(executeCodeRequest);

            List < String > outputList = executeCodeResponse.getOutputList();

            // 5）根据沙箱的执行结果，设置题目的判题状态和信息
            JudgeContext judgeContext = new JudgeContext();
            judgeContext.setJudgeInfo(executeCodeResponse.getJudgeInfo());
            judgeContext.setInputList(inputList);
            judgeContext.setOutputList(outputList);
            judgeContext.setJudgeCaseList(judgeCaseList);
            judgeContext.setQuestion(question);
            judgeContext.setQuestionSubmit(questionSubmit);
            JudgeInfo judgeInfo = judgeManager.doJudge(judgeContext);
            // 6）修改数据库中的判题结果
            questionSubmitUpdate = new QuestionSubmit();
            questionSubmitUpdate.setId(questionSubmitId);
            questionSubmitUpdate.setStatus(QuestionSubmitStatusEnum.SUCCEED.getValue());
            questionSubmitUpdate.setJudgeInfo(JSONUtil.toJsonStr(judgeInfo));
            update = questionSubmitService.updateById(questionSubmitUpdate);
            if (!update) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "题目状态更新错误");
            }
            QuestionSubmit questionSubmitResult = questionSubmitService.getById(questionId);

            return questionSubmitResult;

        } else if (judgmentMethod.equals(QuestionSubmitJudgmentMethodEnum.AI.getValue())) {
            //  第三方代码沙箱(ai的api调用)
            ExecuteCodeResponse executeCodeResponse=this.executeCode(executeCodeRequest);

            List < String > outputList = executeCodeResponse.getOutputList();

            // 5）根据沙箱的执行结果，设置题目的判题状态和信息
            JudgeContext judgeContext = new JudgeContext();
            judgeContext.setJudgeInfo(executeCodeResponse.getJudgeInfo());
            judgeContext.setInputList(inputList);
            judgeContext.setOutputList(outputList);
            judgeContext.setJudgeCaseList(judgeCaseList);
            judgeContext.setQuestion(question);
            judgeContext.setQuestionSubmit(questionSubmit);
            JudgeInfo judgeInfo = judgeManager.doJudge(judgeContext);
            // 6）修改数据库中的判题结果
            questionSubmitUpdate = new QuestionSubmit();
            questionSubmitUpdate.setId(questionSubmitId);
            questionSubmitUpdate.setStatus(QuestionSubmitStatusEnum.SUCCEED.getValue());
            questionSubmitUpdate.setJudgeInfo(JSONUtil.toJsonStr(judgeInfo));
            update = questionSubmitService.updateById(questionSubmitUpdate);
            if (!update) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "题目状态更新错误");
            }
            QuestionSubmit questionSubmitResult = questionSubmitService.getById(questionId);
            return questionSubmitResult;
        }

        return null;

    }


    public ExecuteCodeResponse executeCode(ExecuteCodeRequest executeCodeRequest) {

        String code = executeCodeRequest.getCode();
        String language = executeCodeRequest.getLanguage();
        List<String> inputList = executeCodeRequest.getInputList();
        String string = StrUtil.toString(inputList);

        String prompt = "你是一个编程语言代码执行器，你需要根据编程语言和代码，执行代码，" +
                "并返回执行结果，同时需要返回执行结果的内存和时间，可用模拟数据返回，内存不能超过100" +
                "执行的代码为" + code + "执行的编程语言为" + language + "该代码的输入用例为" + string +
                "请返回代码的执行结果的标准结果为" +
                "{\"outputList\":[\"3\"],\"message\":null,\"status\":1,\"judgeInfo\":{\"message\":null,\"memory\":null,\"time\":124}}" +
                "不要返回任何多余的信息，" +
                "如果代码有错误，请返回Wrong Answer在judgeInfo里面的message，如果执行成功返回Accepted，" +
                "如果运行成功，把status设置为1" +
                "把运行后的答案放入outputList中";

        String res = chatService.doChat(prompt);
        if(res.contains("```json")||res.contains("```"))
        {
            res=   res.substring(res.indexOf("{"), res.lastIndexOf("}") + 1);

        }

        System.out.println("ai改题");


        return JSONUtil.toBean(res, ExecuteCodeResponse.class);
    }
}
